package pl.drypisy;



import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;

import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;
/** 
 * Loads checkpoints, invokes Task, manages overlays, starts and resumes game
 * @author Marcin Pilat
 * @version 1.0
 */
public class Game {
	
	private ArrayList<Checkpoint> checkpointList;
	private PlayMapActivity context;
	private MapView mapView;
	private MapController mc;
	private List<Overlay> lofO;
	private Drawable old;
	private Drawable next;
	private CheckpointItemizedOverlay oldOverlay;
	private CheckpointItemizedOverlay nextOverlay;
	private Checkpoint actPoint;
	private int points;
	private int actId;
	private int accuracy = 30;
	private boolean activeTask = false;
	
	private final String PREF_NAME = "Prefs";
	private final String PREF_CHP = "chid";
	private final String PREF_ROUTE = "rid";
	private final String PREF_POINTS = "points";
	private final String PREF_ACU = "accuracy";
	private SharedPreferences pref;
	
	//Options view
	private TextView acuText;
	private SeekBar seek;
	
	private DBAdapter base;
	
	/**
	 * Public constructor. Initializing variables.
	 * @param gameName Name of current game. Useless
	 * @param mView Handler to MapView from PlayMapActivity
	 * @param c Handler to context
	 */
	public Game(String gameName, MapView mView, PlayMapActivity c){
		checkpointList = new ArrayList<Checkpoint>();
		mapView = mView;
		context = c;
		lofO = mapView.getOverlays();
		old = context.getResources().getDrawable(R.drawable.black_old);
		oldOverlay = new CheckpointItemizedOverlay(old,mapView);
		next = context.getResources().getDrawable(R.drawable.black_new);
		nextOverlay = new CheckpointItemizedOverlay(next,mapView);
		mc = mapView.getController();
		points = 0;
		actId = 0;
		base = new DBAdapter(context);
		pref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
	}
	
	/**
	 * Loading checkpointList from database
	 * @param rid
	 * @return true if route exist in database
	 */
	public boolean loadCheckpointList(int rid){
		base.open();
		Cursor c = base.getCheckpoints(rid);
		base.close();
		if (c.moveToFirst()){
			do{
				checkpointList.add(Checkpoint.getCheckpointFromCursor(c));
			}while (c.moveToNext());
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * Start new game: loading checkpoint list, add first marker and overlays.
	 * @param rid Id of route which will be played
	 */
	public void start(int rid){
		loadCheckpointList(rid);
        //1st point
        actPoint = checkpointList.get(0);
        OverlayItem item = new OverlayItem(actPoint.getGeoPoint(), actPoint.getName(), actPoint.getTask());
        nextOverlay.addOverlay(item);
        mc.animateTo(actPoint.getGeoPoint());
		mc.setZoom(15);
        lofO.clear();
        lofO.add(nextOverlay);
        lofO.add(oldOverlay);
	}
	
	/**
	 * Check if phone is near actual checkpoint
	 * @param l Current Location
	 * @return Distance to current point
	 */
	public int checkLocation(Location l){
		//making Location object for distanceTo()
		Location actL = new Location(l);
		actL.setLatitude(actPoint.getLatitude());
		actL.setLongitude(actPoint.getLongitude());
		float dist = l.distanceTo(actL);
		if (dist < l.getAccuracy()+ accuracy && l.getAccuracy() < 50 && !activeTask){
			Log.d("Distance", "Distance: " + dist + " Accuracy: " + l.getAccuracy() + accuracy );
			activeTask = true;
			soundNotification();
			final AlertDialog.Builder builder = new AlertDialog.Builder(context);
    	    builder.setMessage(context.getString(R.string.reached_point))
    	           .setCancelable(false)
    	           .setPositiveButton(context.getString(R.string.to_task), new DialogInterface.OnClickListener() {
    	               public void onClick(DialogInterface dialog, int id) {
    	            	   goToTask();
    	               }
    	           });
    	    final AlertDialog alert = builder.create();
    	    alert.show();
			return 0;
		} else {
			return (int)dist;
		}
	}
	
	/**
	 * Starting TaskActivity
	 */
	public void goToTask(){
		Intent task = new Intent("pl.drypisy.TASK");
		Bundle extras = new Bundle();
		extras.putInt("chid", actPoint.getChId());
		task.putExtras(extras);
		context.startActivityForResult(task,1);
	}
	
	/**
	 * Jumping to checkpoint after resuming game
	 * @param rid Route id
	 * @param chid Checkpoint id
	 * @param p Points
	 */
	public void goToCheckpoint(int rid, int chid, int p){
		points = p;
    	loadCheckpointList(rid);
        lofO.add(nextOverlay);   
    	Log.d("goTo", "Skacze do " + chid + " w rid: " + rid);
    	actPoint = checkpointList.get(0);
    	--actId; //because of index in next/fastNext functions
    	for (Checkpoint ch : checkpointList){
    		if (ch.getChId() != chid){
    			fastNext();
    			Log.d("fastNext","CheckopinId" + ch.getChId());
    		} else {
    			next(0);
    			break;
    		}
    	}
    }
	
	//Go to next checkpoint. Change Overlays and displaying ending dialog if game is ended. Will be private
	/**
	 * After finish() in TaskActivity. Add new  actual marker and old marker. When there isn't next point finish game. 
	 * @param p points which player gain in TaskActivity
	 * @return actual checkpoint ID
	 */
	public int next(int p){
		if (actId >= checkpointList.size()) return -1;
		Log.d("next","Punkt nr: " + actPoint.getChId());
		points += p;
		checkpointList.get(actId).setPoints(p);
		++actId;
		Log.d("ActId"," : " + actId);
		if (actId < checkpointList.size()){
			activeTask = false;
			//adding old point to old points overlay
	        OverlayItem item = new OverlayItem(actPoint.getGeoPoint(), actPoint.getName(), actPoint.getTask());
	        oldOverlay.addOverlay(item);
	        Log.d("next add overlay","dodaje oldoverlay nr: " + actPoint.getChId());
	        if (!(lofO.contains(oldOverlay))){
	        	lofO.add(oldOverlay);
	        }
	        //getting new point, updating new point overlay
	        actPoint = checkpointList.get(actId);
	        item = new OverlayItem(actPoint.getGeoPoint(), actPoint.getName(), actPoint.getTask());
	        nextOverlay.clearOverlay();
	        nextOverlay.addOverlay(item);
	        mc.animateTo(actPoint.getGeoPoint());
		} else  {
			endingDialog();
    	    OverlayItem item = new OverlayItem(actPoint.getGeoPoint(), actPoint.getName(), actPoint.getTask());
	        oldOverlay.addOverlay(item);
	        nextOverlay.clearOverlay();
		}
		return actPoint.getChId();
	}
	
	//When player reasumes game this function draw overlay with 'old' markers
	private void fastNext(){
		++actId;
		Log.d("ActIdFast"," : " + actId);
		if (actId < checkpointList.size()){
			actPoint = checkpointList.get(actId);
			//adding old point to old points overlay
	        OverlayItem item = new OverlayItem(actPoint.getGeoPoint(), actPoint.getName(), actPoint.getTask());
	        oldOverlay.addOverlay(item);
	        if (!(lofO.contains(oldOverlay))){
	        	lofO.add(oldOverlay);
	        }
		} else  {
			endingDialog();
    	    OverlayItem item = new OverlayItem(actPoint.getGeoPoint(), actPoint.getName(), actPoint.getTask());
	        oldOverlay.addOverlay(item);
	        nextOverlay.clearOverlay();
		}
	}
	
	/**
	 * Displaing dialog to change accuracy. Sending information about players accuracy to PlayMapActivity
	 */
	public void setAccuracy(){
		LinearLayout lay = new LinearLayout(context);
		lay.setOrientation(LinearLayout.VERTICAL);
		lay.setPadding(20, 0, 20, 0);
		acuText = new TextView(context);
		accuracy = pref.getInt(PREF_ACU, accuracy);
		acuText.setText("" + accuracy);
		acuText.setTextSize(25);
		acuText.setGravity(Gravity.CENTER);
		seek = new SeekBar(context);
		seek.setMax(50);
		seek.setProgress(accuracy-20);
		seek.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
			
			public void onStopTrackingTouch(SeekBar seekBar) {}
			public void onStartTrackingTouch(SeekBar seekBar) {}
			
			public void onProgressChanged(SeekBar seekBar, int progress,
					boolean fromUser) {
				int tmp = progress + 20;
				acuText.setText("" + tmp);
			}
		});
		lay.addView(seek);
		lay.addView(acuText);
		final AlertDialog.Builder builder = new AlertDialog.Builder(context);
	    builder.setMessage(context.getString(R.string.setAcuDialog))
		    .setView(lay)
		    .setPositiveButton(context.getString(R.string.setAcuBtn), new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
					accuracy = seek.getProgress() + 20;	
					context.setAccuracyText();
					SharedPreferences.Editor editor = pref.edit();
					editor.putInt(PREF_ACU, accuracy);
					editor.commit();
				}
			})
	        .setCancelable(true);
	    final AlertDialog alert = builder.create();
	    alert.show();
	}
	
	/**
	 * Displaying ending Dialog and ending game
	 */
	private void endingDialog(){
		final AlertDialog.Builder builder = new AlertDialog.Builder(context);
	    builder.setMessage(context.getString(R.string.congr1)+ points +context.getString(R.string.congr2))
	    .setPositiveButton("wyjdź", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int which) {
				SharedPreferences.Editor editor = pref.edit();
				
				//putting values to sharedPreferences
				editor.remove(PREF_CHP);
				editor.remove(PREF_ROUTE);
				editor.remove(PREF_POINTS);
				editor.commit();
				context.finish();
			}
		})
	           .setCancelable(false);
	    final AlertDialog alert = builder.create();
	    alert.show();
	}
	
	//Playing a notification - use when phone is near actual checkpoint location
	private void soundNotification(){
		Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
		Ringtone sound = RingtoneManager.getRingtone(context, notification);
		sound.play();
	}
	
	public int getAccuracy(){
		return accuracy;
	}
}
